/*
----------------------------------------------------------------------------------------------------
This source file is part of the Gamut Framework
Copyright (c) 2007 by Ryan Holcombe

This program is free software; you can redistribute it and/or modify it under the terms of the GNU
Lesser General Public License as published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
----------------------------------------------------------------------------------------------------
*/


#ifndef _Logger_h_
#define _Logger_h_

#include "GamutILogListener.h"
#include "Singleton.h"
#include <boost/shared_ptr.hpp>
#include <string>
#include <list>


#define LOG1( linetext ) \
	Gamut::Logger::getSingleton().logEvent(__FILE__, __LINE__, EXCEPTION, std::string(linetext))
#define LOG2( linetext ) \
	Gamut::Logger::getSingleton().logEvent(__FILE__, __LINE__, WARNING, std::string(linetext))
#define LOG3( linetext ) \
	Gamut::Logger::getSingleton().logEvent(__FILE__, __LINE__, NORMAL, std::string(linetext))
#define LOG4( linetext ) \
	Gamut::Logger::getSingleton().logEvent(__FILE__, __LINE__, INFORMATIONAL, std::string(linetext))

#define LOGF1( linetext, s... ) \
	Gamut::Logger::getSingleton().logEvent(__FILE__, __LINE__, EXCEPTION, linetext, s)
#define LOGF2( linetext, s... ) \
	Gamut::Logger::getSingleton().logEvent(__FILE__, __LINE__, WARNING, linetext, s)
#define LOGF3( linetext, s... ) \
	Gamut::Logger::getSingleton().logEvent(__FILE__, __LINE__, NORMAL, linetext, s)
#define LOGF4( linetext, s... ) \
	Gamut::Logger::getSingleton().logEvent(__FILE__, __LINE__, INFORMATIONAL, linetext, s)


typedef boost::shared_ptr<Gamut::ILogListener> IListenerPtr;
typedef std::list<IListenerPtr> ListenerList;


namespace Gamut
{

	/**
 		Logger handles all logging for the framework. It outputs information received
		to any listeners attached to it

		\remarks
			Logs are generated by the define macros based on the current logging level
	*/

	class Logger : public Singleton<Logger>
	{
	private:
		//! logging level
		LogLevel mLogLevel;
	
		//! list of attached listeners
		ListenerList mListener;

	public:
		/** Default constructor
			\brief creates a log manager that requires listeners
			\param[in] level default log level
		*/
		Logger(LogLevel level = NORMAL);

	
		/** Constructor
 			\brief all logging will be directed to an output file and any listeners
			\param[in] filename log output here
			\param[in] level default log level
		*/
		Logger(const std::string& filename, LogLevel level = NORMAL);
		
	
		/** Default deconstructor
			\brief destroys any attached listeners
		*/
		~Logger();
		
	
		/**
 			\brief writes an entry to all attached listeners
			\param[in] file src file this entry was generated from
			\param[in] line line in src
			\param[in] level what the log level of this entry is
			\param[in] msg log text in std::string format
			\remarks
				this function is not meant to be used directly, but should be called from one
				of the LOG macros
				(i.e. LOG("Error Occurred in " + error); )
		*/
		void logEvent(const std::string& file, int line, LogLevel level, const std::string& msg);
		
		
		/**
 			\brief writes an entry to all attached listeners
			\param[in] file src file this entry was generated from
			\param[in] line line in src
			\param[in] level what the log level of this entry is
			\param[in] msg log text in (char *msg, ...) format
			\remarks
				this function is not meant to be used directly, but should be called from one
				of the LOGF macros. It can be used similarly to printf
				(i.e. LOGF1("Error occurred %d", i); )
		*/
		void logEvent(const std::string& file, int line, const LogLevel level, const char *msg, ...);
		
		
		/**
 			\brief adds a log listener object
			\param[in] listener pointer to the listener object
			\return the listener after it has been added
		*/
		IListenerPtr addListener(IListenerPtr listener);
		
		
		/**
			\brief removes a listener from the list, but does not delete the memory associated with it
			\param[in] listener pointer to the listener object
		*/
		void removeListener(IListenerPtr listener);
		
		
		/**
 			\brief remove the listener from the list
			\param[in] listener pointer to the listener object
		*/
		
		void destroyListener(IListenerPtr listener);


		/**
 			\brief sets the logging level
			\param[in] level 1 is for warnings/errors only, 2 is default, 3 is log everything
		*/
		void setLogLevel(LogLevel level) { mLogLevel = level; }
	};
	
}

#endif
